#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "queue_generation.h"

//выделяет память под строку длиной length символов
char *alloc_string(int length) {
    return (char *) malloc(sizeof(char) * (length + 1));
}

//возвращает новую пустую строку
char *new_empty_string() {
    char *new_empty = alloc_string(0);
    new_empty[0] = '\0';
    return new_empty;
}

//возвращает новое имя для алиаса используемого для tags_paths при поиске тега tag
char *new_alias_name(const char *tag) {
    const char *alias_pattern = "search_%s";

    int name_length = strlen(alias_pattern)
        + strlen(tag)
        - 2; //-2 на %s
    char *new_name = alloc_string(name_length);

    sprintf(new_name, alias_pattern, tag);
    return new_name;
}

//возвращает новую строку полученную конкатенацией строк str1 и str2
char *new_concat_string(const char *str1, const char *str2) {
    int concat_str_length = strlen(str1) + strlen(str2);
    char *new_concat_str = alloc_string(concat_str_length);
    
    sprintf(new_concat_str, "%s%s", str1, str2);
    return new_concat_str;
}


/*
 * запрос для выбора адреса изображения из базы по нескольким тегам
 * имеет следующий вид:
 *
 * -- головная часть ----------------------------------------------
 * SELECT DISTINCT paths.path FROM paths
 * JOIN tags_paths first ON paths.id = first.path_id
 * -- хвостовая часть ---------------------------------------------
 * JOIN tags_paths second ON first.path_id = second.path_id
 *                        AND second.tag_id = (SELECT id
 *                              FROM tags WHERE tag = 'tag1')
 * JOIN tags_paths third ON second.path_id = third.path_id
 *                       AND third.tag_id = (SELECT id
 *                              FROM tags WHERE tag = 'tag2')
 * -- и т.д. для tag3, tag4, tag5 ... -----------------------------
 */


//возвращает новую головную часть запроса
char *new_head_queue(const char *first_alias) {
    const char *head_pattern = 
        //SELECT DISTINCT paths.path FROM paths
        "SELECT DISTINCT paths.path FROM paths "
        //JOIN tags_paths first_alias ON paths.id = first_alias.path_id
        "JOIN tags_paths %s ON paths.id = %s.path_id\n";

    int head_length = strlen(head_pattern)
        + 2 * strlen(first_alias) //встречается в двух местах
        - 4; //-4 на %s
    char *new_head = alloc_string(head_length);

    sprintf(new_head, head_pattern, first_alias, first_alias);
    return new_head;
}

//возвращает новый сегмент хвостовой части
char *new_tail_part(const char *head_alias, const char *part_alias, const char *tag) {
    const char *part_pattern =
        //JOIN tags_paths part_alias
        "JOIN tags_paths %s "
        //ON head_alias.path_id = part_alias.path_id
        "ON %s.path_id = %s.path_id "
        //AND part_alias.tag_id = (SELECT id from tags WHERE tag = 'tag')
        "AND %s.tag_id = (SELECT id from tags WHERE tag = \'%s\')\n";

    int part_length = strlen(part_pattern)
        + strlen(head_alias)
        + 3 * strlen(part_alias)
        + strlen(tag)
        - 10; //-10 на %s
    char *new_part = alloc_string(part_length);

    sprintf(new_part, part_pattern, part_alias, head_alias, part_alias, part_alias, tag);
    return new_part;
}

//возвращает новую "хвостовую" часть запроса
char *new_tail_queue(const char *head_alias, char *tags[]) {
    char *part_alias;
    char *prev_alias;

    char *old_tail;
    char *tail;
    
    char *cur_part;
    
    int i = 0;
    prev_alias = new_concat_string(head_alias, "");
    tail = new_empty_string();
    while(tags[i] != NULL) {
        //генерация имени для алиаса используемого в этой части
        part_alias = new_alias_name(tags[i]);

        old_tail = tail;
        //генерация новой части "хвоста"
        cur_part = new_tail_part(prev_alias, part_alias, tags[i]);
        //наращивание новой части в конец хвоста
        tail = new_concat_string(old_tail, cur_part);

        free(prev_alias);
        //алиас текущей части будет использован в генерации следующей
        //в качестве "головного"
        prev_alias = part_alias;
        
        free(cur_part);
        free(old_tail);
        i++;
    }
    
    free(prev_alias);

    return tail;
}

char *new_queue(char *tags[]) {
    char *head = new_head_queue("head");
    char *tail = new_tail_queue("head", tags);
    
    char *queue = new_concat_string(head, tail);
    
    free(head);
    free(tail);

    return queue;
}

